﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Itau.ST.Log;
using itau.im.entidade;
using System.Configuration;
using NK_Atualiza_Duration.Util;

namespace NK_Atualiza_Duration.Business.Principal
{
    public class Principal : IDisposable
    {
        #region Métodos
        
        #region Principal
        
        public void GerarHistorico() 
        {

            string[] curvasParaAlteracao = new string [1];

            string[] curvasBullet = new string[1];

            string[] periodoHistorico = new string[1];

            // Carregando dados do Arquivo Config

            CarregaConfig(ref curvasParaAlteracao, ref curvasBullet, ref periodoHistorico);

            //---------------------------------------


            // Valida se há o mesmo número de curva PMT e Bullet

            if (curvasParaAlteracao.Length == curvasBullet.Length)
            {
                for (int qtd = 0; qtd < curvasParaAlteracao.Length; qtd++) 
                {
                    IList<RegistroExecucaoCurva> listaPMTs;
                    IList<RegistroExecucaoCurva> listaBullets;

                    // Verifica se há alguma data para carga Histórica
                    if (periodoHistorico[0].Trim().Equals(""))
                    {
                        Util.Log.GravarLog("I", "Não foi inserido nenhum período, para esta carga.");

                        listaPMTs = ObterRegistrosExecucaoCurvaPorCurvaVigente(Convert.ToInt32(curvasParaAlteracao[qtd]));

                        listaBullets = ObterRegistrosExecucaoCurvaPorCurvaVigente(Convert.ToInt32(curvasBullet[qtd]));
                    }
                    else
                    {
                        Util.Log.GravarLog("I", string.Format("Foi inserido um perído para Carga, Início : {0}, Fim : {1}.", periodoHistorico[0], periodoHistorico[1]));

                        listaPMTs = ObterRegistrosExecucaoCurvaPorCurvaVigente(Convert.ToInt32(curvasParaAlteracao[qtd]));

                        listaBullets = ObterRegistrosExecucaoCurvaPorCurvaVigente(Convert.ToInt32(curvasBullet[qtd]));
                        
                        DateTime dtInicial = new DateTime();

                        DateTime dtFinal = new DateTime();

                        try
                        {
                            dtInicial = Convert.ToDateTime(periodoHistorico[0]);


                            dtFinal = Convert.ToDateTime(periodoHistorico[1] + " 23:59");
                           
                        }
                        catch (Exception ex )
                        {
                            Util.Log.GravarLog("E", "Erro para a conversão de Datas para o Histórico. Erro : " + ex.Message);
                            Util.Log.finalizaLog(ClsBatch.enum_TipoFimLogBatch.tipoFimLog_erro);
                            System.Environment.Exit(-1);
                        }

                        // Se houver datas para a carga, realiza uma consulta para trazer as curvas dentro do
                        // período selecionado

                        var listaPMTPeriodo = from PMT in listaPMTs
                                              where PMT.DataHoraExecucaoCurva >= dtInicial && PMT.DataHoraExecucaoCurva <= dtFinal
                                              select PMT;

                        listaPMTs = listaPMTPeriodo.ToList();

                        listaPMTPeriodo = null;



                        var listaBulletPeriodo = from BULLET in listaBullets
                                                 where BULLET.DataHoraExecucaoCurva >= dtInicial && BULLET.DataHoraExecucaoCurva <= dtFinal
                                                 select BULLET;

                        listaBullets = listaBulletPeriodo.ToList();

                        listaBulletPeriodo = null;   
                        //-----------------------------------------------------------------------------------

                    }

                    Util.Log.GravarLog("I", string.Format("Foram encontradas {0} ocorrência(s) para a curva com o ID : {1}", listaPMTs.Count, curvasParaAlteracao[qtd]));


                    // Para cada interação da curva do Tipo PMT, e carregado os seus pontos e carregada os pontos da curva bullet para esta
                    // Curva PMT, feito isso e criado uma Lista com os dados dos vértices da curva bullet com as Datas da curva PMT
                    // para aí então realizar o cálculo do Duration.

                    listaPMTs.ToList().ForEach(curva =>
                    {
                        Util.Log.GravarLog("I", string.Format("Início de busca de dados para a Curva : {0}, horário de DataInclusaoVigencia: {1} ", curva.CodigoCurva, curva.DataInclusaoVigencia));

                        var curvaBullet = from curvaB in listaBullets
                                          where curvaB.DataHoraExecucaoCurva == curva.DataHoraExecucaoCurva
                                          select curvaB;

                        if (curvaBullet.ToList().Count > 0) 
                        {
                            IList<CurvaExecucaoPonto> listaPontosPMT = buscaProjecaoCurva(curva.CodigoCurva, curva.DataInclusaoVigencia, curva.DataHoraExecucaoCurva);

                            IList<CurvaExecucaoPonto> listaPontosBullet = buscaProjecaoCurva(curvaBullet.ToList()[0].CodigoCurva, curvaBullet.ToList()[0].DataInclusaoVigencia, curvaBullet.ToList()[0].DataHoraExecucaoCurva);

                            IList<CurvaExecucaoPonto> listaPontosAtualiza = new List<CurvaExecucaoPonto>();

                            if (listaPontosPMT.Count > 0)
                            {
                                listaPontosPMT.ToList().ForEach(pPmt =>
                                {
                                    var listPBullet = from bullet in listaPontosBullet
                                                      where bullet.DataVencimento == pPmt.DataVencimento
                                                      select bullet;

                                    pPmt.ValorVertice = listPBullet.ToList()[0].ValorVertice;

                                    listaPontosAtualiza.Add(pPmt);

                                });

                                CalcularDurationNovo(ref listaPontosAtualiza);

                                AtualizaPontos(listaPontosAtualiza);

                            }
                            else
                            {
                                Util.Log.GravarLog("I",string.Format("Não foi encontrato nenhum ponto para a Curva ID : {0},Data de Inclusão : {1} e Horário de Execução: {2}"
                                        ,curva.CodigoCurva,curva.DataInclusaoVigencia.ToString("yyyy-MM-dd-hh.mm.ss.ffffff"),curva.DataHoraExecucaoCurva.ToString("yyyy-MM-dd-hh.mm.ss.ffffff")));
                            }                            
                        }

                    });
                    //-------------------------------------------------------------------------------------------------------------------
                }
               
                Util.Log.finalizaLog(ClsBatch.enum_TipoFimLogBatch.tipoFimLog_normal);
            }
            else
            {
                Util.Log.GravarLog("I", "Não foi informado o mesmo número de curvas Bullet para as curvas Pmt, ou vice-versa");
                Util.Log.finalizaLog(ClsBatch.enum_TipoFimLogBatch.tipoFimLog_erro);
                System.Environment.Exit(-1);

            }

        }
        
        #endregion

        #region Auxiliares

        private void CalcularDurationNovo(ref IList<CurvaExecucaoPonto> listaVertices)
        {
            //formula
            double valorMatrizDU = 0;
            double valorMatrizDC = 0;
            double valorTotal = 0;
            double FatorVertice = 0;


            foreach (CurvaExecucaoPonto item in listaVertices)
            {
                FatorVertice = (1/item.ValorVertice);

                valorMatrizDC += item.QuantidadeDiasCorridos * FatorVertice;
                valorMatrizDU += item.QuantidadeDiasUteis * FatorVertice;
                valorTotal += FatorVertice;
                item.DurationDiasCorridos = valorMatrizDC / valorTotal;
                item.DurationDiasUteis = valorMatrizDU / valorTotal;
                FatorVertice = 0;
            }
        }

        private void AtualizaPontos(IList<CurvaExecucaoPonto> listPontos)
        {
            using (DAO.DB dbCurva = new NK_Atualiza_Duration.DAO.DB())
            {
                if (DAO.DB.ConectaDb2())
                {
                    Util.Log.GravarLog("I", "Atualizando pontos da curva");
                    dbCurva.AtualizaPontoCurva(listPontos);                   
                }
                else
                {
                    Util.Log.GravarLog("I", "Não foi possível executar o método(AtualizaPontos).");
                   
                }
            }
        }

        private IList<RegistroExecucaoCurva> ObterRegistrosExecucaoCurvaPorCurvaVigente(int iCurva)
        {
            using (DAO.DB dbCurva = new NK_Atualiza_Duration.DAO.DB())
            {
                if (DAO.DB.ConectaDb2())
                {
                    Util.Log.GravarLog("I", string.Format("Busca da curva: {0}, relizada com sucesso.",iCurva));

                    return dbCurva.ObterRegistrosExecucaoCurvaPorCurvaVigente(iCurva);
                }
                else
                {
                    Util.Log.GravarLog("I", "Não foi possível executar o método(ObterRegistrosExecucaoCurvaPorCurvaVigente).");
                    return new List<RegistroExecucaoCurva>();
                }
            }
        }

        private IList<CurvaExecucaoPonto> buscaProjecaoCurva(int intCodigoCurva, DateTime dtDateInclusaoCurva, DateTime dtHoraExcucao) 
        {
            using (DAO.DB dbCurva = new NK_Atualiza_Duration.DAO.DB())
            {
                if (DAO.DB.ConectaDb2())
                {
                    Util.Log.GravarLog("I", "Realizando a busca dos pontos da curva : " + intCodigoCurva);
                    return dbCurva.buscaProjecaoCurva(intCodigoCurva, dtDateInclusaoCurva, dtHoraExcucao);
                }
                else
                {
                    Util.Log.GravarLog("I", "Não foi possível executar o método(buscaProjecaoCurva).");
                    return new List<CurvaExecucaoPonto>();
                }
            }
        
        }               

        private void CalcularDuration(ref IList<CurvaExecucaoPonto> listaVertices)
         {
             //formula
             double valorMatrizDU = 0;
             double valorMatrizDC = 0;
             double valorTotal = 0;

             foreach (CurvaExecucaoPonto item in listaVertices)
             {
                 valorMatrizDC += (double)item.QuantidadeDiasCorridos * item.ValorVertice;
                 valorMatrizDU += (double)item.QuantidadeDiasUteis * item.ValorVertice;
                 valorTotal += item.ValorVertice;
                 item.DurationDiasCorridos = valorMatrizDC / valorTotal;
                 item.DurationDiasUteis = valorMatrizDU / valorTotal;
             }


         }

        private void CarregaConfig(ref string[] curvasParaAlteracao, ref string[] curvasBullet, ref string[] periodoHistorico)
        {
            Util.Log.IniciaLog(Config.RetornarValorAppSettings("NomeRotina"));

            // Carregando dados do Arquivo Config

            curvasParaAlteracao = Config.RetornarValorAppSettings("CurvasParaAlteracao").Split(',');

            curvasBullet = Config.RetornarValorAppSettings("CurvasParaAlteracaoBullet").Split(',');

            periodoHistorico = Config.RetornarValorAppSettings("PeriodoHistorico").Split(',');
            //---------------------------------------

        }

        #endregion

        #region IDisposable Members

        public void Dispose()
         {
             
             GC.SuppressFinalize(this);
             
         }

         #endregion
       
        #endregion
    }
}
